
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                               proc.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"
#include "tty.h"
#include "console.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"

/*======================================================================*
                              schedule
 *======================================================================*/
PUBLIC void schedule()
{
	PROCESS* p;
	int	 greatest_ticks = 0;
	for ( p = proc_table; p<proc_table+NR_TASKS; p++)
	{
		if (p->sleep>0)
		{
			p->sleep--;
		}
	}
	
	while (!greatest_ticks) {
		for (p = proc_table; p < proc_table+NR_TASKS; p++) {
			if (p->wait>0 || p->sleep>0)
			{
				continue;//wait or sleep, no slide
			}
			
			if (p->ticks > greatest_ticks) {
				greatest_ticks = p->ticks;
				p_proc_ready = p;
			}
		}

		if (!greatest_ticks) {
			for (p = proc_table; p < proc_table+NR_TASKS; p++) {
				if (p->wait>0 || p->sleep>0)
				{
					continue;
				}
				p->ticks = p->priority;
			}
		}
	}
}

/*======================================================================*
                           sys_get_ticks
 *======================================================================*/
PUBLIC int sys_get_ticks()
{
	return ticks;
}

PUBLIC void sys_disp_str(char* str)
{
	TTY* p_tty = tty_table;
	int i = 0;
	int z = p_proc_ready - proc_table -1;
	while (str[i]!='\0')
	{
		cus_out_char(p_tty->p_console, str[i], z);
		i++;
	}
}

PUBLIC void sys_process_sleep(int k)
{
	p_proc_ready->sleep = k*HZ/1000;
	schedule();
}


PUBLIC void sys_P(SEMAPHORE* sp)
{
	sp->count--;
	if (sp->count<0)
	{
		p_proc_ready->wait = 1;
		sp->queue[sp->ptr] = p_proc_ready;
		sp->ptr++;
		schedule();
	}
}

PUBLIC void sys_V(SEMAPHORE* sp)
{
	sp->count++;
	if (sp->count<=0)
	{
		sp->queue[0]->wait = 0;
		for (int i = 0; i < sp->ptr; i++)
		{
			sp->queue[i] = sp->queue[i+1];
		}
		sp->ptr--;
	}
}

PUBLIC void init_semaphore(int readnum)
{
	rmutex.count = 1;
	wmutex.count = 1;
	max.count = readnum;
	x.count = 1;
	y.count = 1;
	z.count = 1;
	sp_rmutex = &rmutex;
	sp_wmutex = &wmutex;
	sp_max = &max;
	sp_x = &x;
	sp_y = &y;
	sp_z = &z;
}

PUBLIC void readA()
{
	while (1)
	{
		s_P(sp_z);
		s_P(sp_max);
		s_P(sp_rmutex);
		s_P(sp_x);
		readcount++;
		cur_readNum++;
		if (readcount==1)
		{
			s_P(sp_wmutex);
		}
		s_V(sp_x);
		s_V(sp_rmutex);
		s_V(sp_z);

		read_write = 0;
		s_disp_str("A begins to read.\n", 1);
		//read A costs 2 slides sleep 2 times
		s_disp_str("A is reading.\n", 1);
		s_process_sleep(2000);
		s_disp_str("A is reading.\n", 1);
		s_process_sleep(2000);
		s_disp_str("A ends reading.\n", 1);
		cur_readNum--;
		s_V(sp_max);

		s_P(sp_x);
		readcount--;
		if (readcount==0)
		{
			s_V(sp_wmutex);
		}
		s_V(sp_x);
		// if (maxreadNum==3)
		// {
		// 	s_process_sleep(16000);	//2000 = 2000*1 + 2000*7
		// }
		// else if (maxreadNum==2)
		// {
		// 	s_process_sleep(16000);	// 2000 = 2000*1 + 2000*7
		// }
		// else if (maxreadNum==1)
		// {
		// 	s_process_sleep(26000);	// 12000 = 2000*3 + 2000*3 + 2000*7
		// }
	}
}

PUBLIC void readB()
{
	while (1)
	{
		s_P(sp_z);
		s_P(sp_max);
		s_P(sp_rmutex);
		s_P(sp_x);
		readcount++;
		cur_readNum++;
		if (readcount==1)
		{
			s_P(sp_wmutex);
		}
		s_V(sp_x);
		s_V(sp_rmutex);
		s_V(sp_z);

		read_write = 0;
		s_disp_str("B begins to read.\n", 2);
		//read B costs 3 slides sleep 3 times
		s_disp_str("B is reading.\n", 2);
		s_process_sleep(2000);
		s_disp_str("B is reading.\n", 2);
		s_process_sleep(2000);
		s_disp_str("B is reading.\n", 2);
		s_process_sleep(2000);
		s_disp_str("B ends reading.\n", 2);
		cur_readNum--;
		s_V(sp_max);

		s_P(sp_x);
		readcount--;
		if (readcount==0)
		{
			s_V(sp_wmutex);
		}
		s_V(sp_x);
		// if (maxreadNum==3)
		// {
		// 	s_process_sleep(14000);	// + 2000*7
		// }
		// else if (maxreadNum==2)
		// {
		// 	s_process_sleep(18000);	//4000 = 2000*2 + 2000*7
		// }
		// else if (maxreadNum==1)
		// {
		// 	s_process_sleep(20000);	//6000 = 2000*3 + 2000*7
		// }
	}
}

PUBLIC void readC()
{
	while (1)
	{
		s_P(sp_z);
		s_P(sp_max);
		s_P(sp_rmutex);
		s_P(sp_x);
		readcount++;
		cur_readNum++;
		if (readcount==1)
		{
			s_P(sp_wmutex);
		}
		s_V(sp_x);
		s_V(sp_rmutex);
		s_V(sp_z);

		read_write = 0;
		s_disp_str("C begins to read.\n", 3);
		//read C costs 3 slides sleep 3 times
		s_disp_str("C is reading.\n", 3);
		s_process_sleep(2000);
		s_disp_str("C is reading.\n", 3);
		s_process_sleep(2000);
		s_disp_str("C is reading.\n", 3);
		s_process_sleep(2000);
		s_disp_str("C ends reading.\n", 3);
		cur_readNum--;
		s_V(sp_max);

		s_P(sp_x);
		readcount--;
		if (readcount==0)
		{
			s_V(sp_wmutex);
		}
		s_V(sp_x);
		// if (maxreadNum==3)
		// {
		// 	s_process_sleep(14000);	// + 2000*7
		// }
		// else if (maxreadNum==2)
		// {
		// 	s_process_sleep(14000);	// + 2000*7
		// }
		// else if (maxreadNum==1)
		// {
		// 	s_process_sleep(14000);	// + 2000*7
		// }
	}
}

PUBLIC void writeD()
{
	while (1)
	{
		//s_P(sp_z);
		s_P(sp_y);
		writecount++;
		if (writecount==1)
		{
			s_P(sp_rmutex);
		}
		s_V(sp_y);

		s_P(sp_wmutex);
		read_write = 1;
		s_disp_str("D begins to write.\n", 4);
		//write D costs 3 slides sleep 3 times
		s_disp_str("D is writing.\n", 4);
		s_process_sleep(2000);
		s_disp_str("D is writing.\n", 4);
		s_process_sleep(2000);
		s_disp_str("D is writing.\n", 4);
		s_process_sleep(2000);
		s_disp_str("D ends writing.\n", 4);

		s_V(sp_wmutex);

		s_P(sp_y);
		writecount--;
		if (writecount==0)
		{
			s_V(sp_rmutex);
		}
		s_V(sp_y);
		//s_V(sp_z);
		// if (maxreadNum==3)
		// {
		// 	s_process_sleep(14000);	//35000 = 2000*4 + 2000*3
		// }
		// else if (maxreadNum==2)
		// {
		// 	s_process_sleep(18000);	//45000 = 2000*4 + 2000*5
		// }
		// else if (maxreadNum==1)
		// {
		// 	s_process_sleep(22000);	//55000 = 2000*4 + 2000*1 + 2000*3 + 2000*3
		// }
	}
}

PUBLIC void writeE()
{
	while (1)
	{
		//s_P(sp_z);
		s_P(sp_y);
		writecount++;
		if (writecount==1)
		{
			s_P(sp_rmutex);
		}
		s_V(sp_y);

		s_P(sp_wmutex);
		read_write = 1;
		s_disp_str("E begins to write.\n", 5);
		//write E costs 4 slides sleep 4 times
		s_disp_str("E is writing.\n", 5);
		s_process_sleep(2000);
		s_disp_str("E is writing.\n", 5);
		s_process_sleep(2000);
		s_disp_str("E is writing.\n", 5);
		s_process_sleep(2000);
		s_disp_str("E is writing.\n", 5);
		s_process_sleep(2000);
		s_disp_str("E ends writing.\n", 5);
		read_write = -1;
		s_V(sp_wmutex);

		s_P(sp_y);
		writecount--;
		if (writecount==0)
		{
			s_V(sp_rmutex);
		}
		s_V(sp_y);
		//s_V(sp_z);
		// if (maxreadNum==3)
		// {
		// 	s_process_sleep(6000);	//15000 = 2000*3
		// }
		// else if (maxreadNum==2)
		// {
		// 	s_process_sleep(10000);	//25000 = 2000*5
		// }
		// else if (maxreadNum==1)
		// {
		// 	s_process_sleep(14000);	//30000 = 2000*1 + 2000*3 + 2000*3
		// }
	}
}